package com.epcs.model.dao;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.Transformers;

import com.epcs.model.dto.Account;
import com.epcs.model.dto.Following;
import com.epcs.model.dto.MostFollowingList;
import com.epcs.util.DBUtil;

public class FollowingDAO {
	public List<Following> getAllFollowing(Account account) {

		Session session = null;
		try {
			session = DBUtil.getSession();
			Criteria criteria = session.createCriteria(Following.class);
			Criterion criterion = Restrictions.eq("account", account);
			criteria.add(criterion);
			List<Following> followingList = new ArrayList<Following>();
			followingList = criteria.list();
			if (followingList.size() > 0) {
				return followingList;
			}

		} catch (HibernateException e) {
			System.out.println("Rolback: \n" + e.getMessage());

		} finally {
			if (session != null) {
				session.close();
			}
		}
		return null;
	}

	public Following insertFollowingToDB(Following following) {

		Session session = null;
		Transaction transaction = null;
		try {

			// get session
			session = DBUtil.getSession();
			// open transaction
			transaction = session.beginTransaction();
			session.save(following);
			transaction.commit();

			return following;
		} catch (HibernateException e) {
			transaction.rollback();
			System.out.println("Rolback: \n" + e.getMessage());

		} finally {
			if (session != null) {
				session.close();
			}
		}
		return null;
	}

	public List<Following> getAllCategoryFollowing(Account account) {

		Session session = null;
		try {
			session = DBUtil.getSession();
			Criteria criteria = session.createCriteria(Following.class);
			Criterion criterion = Restrictions.eq("account", account);
			Criterion criterion1 = Restrictions.eq("typeOfFollow", "category");
			criteria.add(criterion).add(criterion1);
			List<Following> followingList = new ArrayList<Following>();
			followingList = criteria.list();
			if (followingList.size() > 0) {
				return followingList;
			}

		} catch (HibernateException e) {
			System.out.println("Rolback: \n" + e.getMessage());

		} finally {
			if (session != null) {
				session.close();
			}
		}
		return null;
	}

	public boolean deleteFollowingCategorybyAccount(Following following) {

		Session session = DBUtil.getSession();
		Transaction trans = null;
		try {
			trans = session.beginTransaction();
			session.delete(following);
			trans.commit();
			return true;
		} catch (HibernateException e) {
			System.out.println(e.getMessage());
			trans.rollback();
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return false;
	}

	public Following loadFollowingEvent(Account account, int idOfEvent) {

		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Following.class);
			criteria.add(Restrictions.eq("account", account)).add(Restrictions.eq("typeOfFollow", "event"))
					.add(Restrictions.eq("idOfFollow", idOfEvent));
			Following following = (Following) criteria.uniqueResult();
			if (following != null) {
				return following;
			}
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return null;
	}

	public Following loadFollowingCategory(Account account, int idOfCategory) {

		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Following.class);
			criteria.add(Restrictions.eq("account", account)).add(Restrictions.eq("typeOfFollow", "category"))
					.add(Restrictions.eq("idOfFollow", idOfCategory));
			Following following = (Following) criteria.uniqueResult();
			if (following != null) {
				return following;
			}
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return null;
	}

	public Following loadFollowingEventById(int id) {

		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Following.class);
			criteria.add(Restrictions.eq("followingId", id));
			Following following = (Following) criteria.uniqueResult();
			if (following != null) {
				return following;
			}
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return null;
	}

	// ----------------------------------------------------------------NHÂN
	public List<Following> getFollowingByEventID(int eventID) {
		Session session = null;
		try {
			session = DBUtil.getSession();
			Criteria criteria = session.createCriteria(Following.class);
			Criterion criterion1 = Restrictions.eq("typeOfFollow", "event");
			Criterion criterion = Restrictions.eq("idOfFollow", eventID);
			criteria.add(criterion).add(criterion1);
			List<Following> followingList = new ArrayList<Following>();
			followingList = criteria.list();
			if (followingList.size() > 0) {
				return followingList;
			}

		} catch (HibernateException e) {
			System.out.println("Rolback: \n" + e.getMessage());

		} finally {
			if (session != null) {
				session.close();
			}
		}
		return null;
	}

	public List<MostFollowingList> getMostFollowingList(int firstPosition, int maxRecord, List<Integer> listEventId) {
		if (listEventId != null) {
			List<MostFollowingList> list = new ArrayList<MostFollowingList>();
			if (listEventId.size() > 0) {
				Session session = null;
				try {
					session = DBUtil.getSession();
					Criteria criteria = session
							.createCriteria(Following.class)

							.setProjection(
									Projections.projectionList()
											.add(Projections.groupProperty("idOfFollow"), "idOfFollow")
											.add(Projections.rowCount(), "countById"))
							.add(Restrictions.eq("typeOfFollow", "event"))
							.add(Restrictions.in("idOfFollow", listEventId)).addOrder(Order.desc("countById"))
							.setFirstResult(firstPosition).setMaxResults(maxRecord)
							.setResultTransformer(Transformers.aliasToBean(MostFollowingList.class));
					list = criteria.list();

					if (list.size() > 0) {
						return list;
					}

				} catch (HibernateException e) {
					System.out.println("Rolback: \n" + e.getMessage());
					e.printStackTrace();
				} finally {
					if (session != null) {
						session.close();
					}
				}

			}
			return list;
		}
		return null;
	}

	// ------------------------DANG------------------//
	public int getNumberOfFollowingByEventID(int idOfEvent) {

		Session session = DBUtil.getSession();
		try {
			ProjectionList projectionList = Projections.projectionList();
			projectionList.add(Projections.rowCount());
			Criteria criteria = session.createCriteria(Following.class);
			criteria.setProjection(projectionList);
			criteria.add(Restrictions.eq("idOfFollow", idOfEvent)).add(Restrictions.eq("typeOfFollow", "event"));

			return ((Long) criteria.uniqueResult()).intValue();

		} finally {
			if (session != null) {
				session.close();
			}
		}
	}

	// ------------------------DANG------------------//
	public int getNumberOfFollowingByCategoryID(int idOfCategory) {

		Session session = DBUtil.getSession();
		try {
			ProjectionList projectionList = Projections.projectionList();
			projectionList.add(Projections.rowCount());
			Criteria criteria = session.createCriteria(Following.class);
			criteria.setProjection(projectionList);
			criteria.add(Restrictions.eq("idOfFollow", idOfCategory)).add(Restrictions.eq("typeOfFollow", "category"));

			return ((Long) criteria.uniqueResult()).intValue();

		} finally {
			if (session != null) {
				session.close();
			}
		}
	}

	public List<Account> getAllAccountFollowEvent(int idOfEvent) {
		Session session = DBUtil.getSession();
		try {
			ProjectionList projectionList = Projections.projectionList();
			projectionList.add(Projections.property("account"));
			Criteria criteria = session.createCriteria(Following.class);
			criteria.setProjection(projectionList);
			criteria.add(Restrictions.eq("idOfFollow", idOfEvent)).add(Restrictions.eq("typeOfFollow", "event"));

			return criteria.list();

		} finally {
			if (session != null) {
				session.close();
			}
		}
	}

	public List<Following> getFollowingEventByAccount(Account account) {

		Session session = null;
		try {
			session = DBUtil.getSession();
			Criteria criteria = session.createCriteria(Following.class);
			Criterion criterion = Restrictions.eq("account", account);
			criteria.add(criterion).add(Restrictions.eq("typeOfFollow", "event"));
			List<Following> followingList = new ArrayList<Following>();
			followingList = criteria.list();
			if (followingList.size() > 0) {
				return followingList;
			}

		} catch (HibernateException e) {
			System.out.println("Rolback: \n" + e.getMessage());

		} finally {
			if (session != null) {
				session.close();
			}
		}
		return null;
	}

	public List<Integer> getCategoryIdListByAccount(Account account) {

		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Following.class);
			criteria.add(Restrictions.eq("account", account)).add(Restrictions.eq("typeOfFollow", "category"))
					.setProjection(Projections.projectionList().add(Projections.property("idOfFollow")));
			List<Integer> listCategoryId = criteria.list();
			if(listCategoryId.size() >0 ){
				return listCategoryId;
			} else {
				return null;
			}

			
		} finally {
			if (session != null) {
				session.close();
			}
		}
	}
	
	public List<Integer> getFollowedCategoryIdListFromSystem() {
		
		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Following.class);
			criteria.add(Restrictions.eq("typeOfFollow", "category"))
			.setProjection(Projections.distinct(Projections.projectionList().add(Projections.property("idOfFollow"))));
			List<Integer> listCategoryId = criteria.list();
			
			return listCategoryId;
		} finally {
			if (session != null) {
				session.close();
			}
		}
	}

	public List<Integer> getEventIdListByAccount(Account account) {

		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Following.class);
			criteria.add(Restrictions.eq("account", account)).add(Restrictions.eq("typeOfFollow", "event"))
					.setProjection(Projections.projectionList().add(Projections.property("idOfFollow")));
			List<Integer> listEventId = criteria.list();
			if (listEventId.size() > 0) {
				return listEventId;
			}
		} finally {
			if (session != null) {
				session.close();
			}
		}
		return null;
	}
	
	public List<Following> getFollowingList(List<Integer> followingIdList, Account account) {
		List<Following> followingList =  new ArrayList<Following>();
		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Following.class);
			Criterion criterion1 =Restrictions.in("followingId", followingIdList);
			Criterion criterion2 = Restrictions.not(Restrictions.eq("account", account));
			criteria.add(criterion1).add(criterion2);
			followingList = criteria.list();
		} finally {
			if (session != null) {
				session.close();
			}
		}
		return followingList;
	}
}
